package com.kusej.gitmanger.utils;

import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.xml.XmlDocument;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.w3c.dom.*;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.kusej.gitmanger.utils.Global.versionFlag;

public class FileModifyUtils {

    public static void updateDesc(Project project, String descText, String sourceBranchName, String targetName) {
        WriteCommandAction.runWriteCommandAction(project, new Runnable() {
            @Override
            public void run() {
                // 不允许在主线程修改文件， 所以包装一层
                try {
                    FileModifyUtils.updateDescInner(UpdateDescParams.builder().project(project).descText(descText).msgText(String.format(Global.descTextFormat, descText, sourceBranchName)).toBranch(targetName).build());
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        });
    }

    /**
     * 使用jdom解析xml，并更新pom.xml
     */
    public static String updateDescInner(UpdateDescParams updateDescParams) throws IOException, GitAPIException {
        String versionName = null;
        // 加载XML文件
        String xmlFilePath = updateDescParams.getProject().getBasePath() + "/pom.xml";
        File inputFile = new File(xmlFilePath);
        try {
            if (inputFile.exists() && inputFile.isFile()) {
                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                DocumentBuilder builder = factory.newDocumentBuilder();
                Document doc = builder.parse(inputFile);
                // 获取根元素
                Element root = doc.getDocumentElement();
                // 获取version标签
                Element version = getSomeElement(root, "version");
                if (version != null) {
                    String textContent = version.getTextContent();
                    String lastName = "";
                    String prefix = "";
                    if (StringUtils.isNotBlank(updateDescParams.getToBranch())) {
                        // 如果toBranch不为空，则需要在版本里增加分支名称,
                        // 例如toBranch：feature-glsw-hotel， textContent：3.6.2-glsw-hotel
                        // 生成的version：3.6.2-glsw-hotel
                        prefix = textContent.contains("-") ? textContent.substring(0, textContent.lastIndexOf("-")) : textContent;
                        lastName = updateDescParams.getToBranch().toLowerCase().replace("feature-", "").replace("feature", "")
                                .replace("master-", "").replace("master", "").replace("main","").replace("main-","");
                        if (StringUtils.isNotBlank(lastName)){
                            lastName = "-" + lastName;
                        }
                    }
                    if (updateDescParams.isMaster()) {
                        if (PropertiesComponent.getInstance(updateDescParams.getProject()).getBoolean(versionFlag)) {
                            prefix = addNum(textContent); // 主分支版本号+1
                        } else { // 主分支版本号不修改
                            prefix = textContent;
                        }
                    }
                    versionName = prefix + lastName;
                    version.setTextContent(versionName);
                    if (StringUtils.isNotBlank(updateDescParams.getDescText())) {
                        // 获取description标签
                        Element description = getSomeElement(root, "description");
                        if (description != null) {
                            description.setTextContent(updateDescParams.getDescText());
                        } else {
                            // 创建新标签
                            Element newTag = doc.createElement("description");
                            newTag.setTextContent(updateDescParams.getDescText());
                            Text newline = doc.createTextNode("\n    ");
                            // 在"version"标签之后插入新标签
                            Node parentNode = version.getParentNode();
                            Node nextSibling = version.getNextSibling();
                            if (nextSibling != null) {
                                parentNode.insertBefore(newline, nextSibling);
                                parentNode.insertBefore(newTag, nextSibling);
                            } else {
                                parentNode.appendChild(newline).appendChild(newTag);
                            }
                        }
                    }
                    // 保存修改后的XML文件
                    TransformerFactory transformerFactory = TransformerFactory.newInstance();
                    Transformer transformer = transformerFactory.newTransformer();
                    DOMSource source = new DOMSource(doc);
                    StreamResult result = new StreamResult(inputFile);
                    transformer.transform(source, result);
                    VirtualFile xmlVirtualFile = LocalFileSystem.getInstance().findFileByPath(xmlFilePath);
                    assert xmlVirtualFile != null;
                    xmlVirtualFile.refresh(false, false);
                    System.out.println("XML file update success");
                } else {
                    System.out.println("xml: version not found");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("parse xml error !");
        }
        GitBranchUtils.commitAndPush(updateDescParams.getProject().getBasePath(), updateDescParams.getMsgText());
        return versionName;
    }

    private static Element getSomeElement(Element root, String version) {
        NodeList childNodes = root.getChildNodes();
        // 遍历子节点，查找version标签
        for (int i = 0; i < childNodes.getLength(); i++) {
            if (childNodes.item(i) instanceof Element) {
                Element childElement = (Element) childNodes.item(i);
                if (childElement.getTagName().equals(version)) {
                    return childElement;
                }
            }
        }
        return null;
    }


    private static String addNum(String input) {
        List<String> split = Arrays.stream(input.split("")).collect(Collectors.toList());
        int lastIndex = -1;
        for (int i = 0; i < split.size(); i++) {
            if (Character.isDigit(split.get(i).charAt(0))) {
                lastIndex = i;
            } else if (Objects.equals("-", split.get(i))) {
                break;
            }
        }
        if (lastIndex > -1) {
            List<String> sub = split.subList(0, lastIndex + 1);
            updateNum(sub, lastIndex);
            return String.join("", sub);// 主分支不需要分支名称结尾了
        }
        return input;
    }

    private static void updateNum(List<String> split, int lastIndex) {
        int addNum;
        if (lastIndex > -1) {// 已经没有上一个字符串了
            if (Character.isDigit(split.get(lastIndex).charAt(0))) {
                addNum = Integer.parseInt(split.get(lastIndex)) + 1;
                if (addNum > 9) {// 需要进位
                    split.set(lastIndex, "0");
                    lastIndex = lastIndex - 1;
                    updateNum(split, lastIndex);
                } else {
                    split.set(lastIndex, String.valueOf(addNum));
                }
            } else {
                split.add(lastIndex + 1, "1");
            }
        } else {
            split.add(0, "1");
        }
    }


    /**
     * PsiFile 需要保存到磁盘， 一次成功，一次失败，无语了
     *
     * @param project
     * @param descText
     */
    private static void updateDescInner(Project project, String descText) {
        String xmlFilePath = project.getBasePath() + "/pom.xml";
        // 获取XML文件
        VirtualFile xmlVirtualFile = LocalFileSystem.getInstance().findFileByPath(xmlFilePath);
        if (xmlVirtualFile == null) {
            System.out.println("pom文件不存在，不需要更新pom.xml 文件描述了");
            return;
        }
        // 将VirtualFile转换为PsiFile
        PsiFile psiFile = PsiManager.getInstance(project).findFile(xmlVirtualFile);
        if (!(psiFile instanceof XmlFile)) {
            return;
        }
        // 获取XML文件的内容
        XmlFile xmlFile = (XmlFile) psiFile;
        XmlDocument document = xmlFile.getDocument();
        if (document == null) {
            System.out.println("pom文件文件解析失败document， 文件描述了");
            return;
        }

        // 获取根标签
        XmlTag rootTag = document.getRootTag();
        if (rootTag == null) {
            System.out.println("pom文件文件解析失败rootTag， 文件描述了");
            return;
        }

        // 获取description标签
        XmlTag descriptionTag = rootTag.findFirstSubTag("description");
        if (descriptionTag == null) {
            System.out.println("pom文件文件解析失败description， 文件描述了");
            return;
        }

        // 修改description标签内容
        descriptionTag.getValue().setText(descText);

        // 保存修改后的XML文件
        xmlFile.navigate(true);
        FileDocumentManager.getInstance().saveDocument(xmlFile.getViewProvider().getDocument());// 保存到磁盘，不然git提交不了
        xmlFile.setName(xmlFile.getName()); // 强制让Idea重新解析文件
        xmlFile.getVirtualFile().refresh(false, false, () -> {
            try {
                System.out.println("FileModifyUtils.updateDescInner:ok--------------------->");
                GitBranchUtils.commitAndPush(project.getBasePath(), descText);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
    }

}
